precision mediump float;

uniform vec2 u_resolution;
/**
* 长方形 box：  1. 原点位于长方形的中心点，形状是轴对称的
* 				2. b表示长方形右上角顶点的坐标
*/
float sdBox( in vec2 p, in vec2 b )
{
    // abs(p)是常用技巧，由于该图形四个象限都是相同的，因此都映射到第一象限即可
    // 现在的d表示长方体右上角顶点直线p点的向量
    vec2 d = abs(p)-b;
    // p点在外部：length(max(d,0.0)), 在内部则是min(max(d.x,d.y),0.0), 这两项总至少有一项为0
    return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}

/**
* 线段：  1. a，b表示线段两个端点的坐标
*/
float sdSegment( in vec2 p, in vec2 a, in vec2 b )
{
    // pa表示a点指向p点的向量， ba表示a点指向b点的向量
    vec2 pa = p-a, ba = b-a;
    // h表示pa在ba上投影的长度占ba长度的比例，限定到[0,1]
    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
    // ba*h 是以a为起点，方向与ba相同，长度等于pa在ba方向上投影的长度的向量
    // pa视为斜边，ba*h是直角边，那么pa - ba*h则是另一条直角边，也就是从p点做垂线垂直于ab，显然该垂线的长度就是所求最短距离
    return length( pa - ba*h );
}
/**
* 菱形：  1. 原点在菱形的中心点，四个顶点都在坐标轴上
*         2. b.x = 与x轴正半轴交点， b.y = 与y轴正半轴交点
*/
float ndot(vec2 a, vec2 b ) { return a.x*b.x - a.y*b.y; }
float sdRhombus( in vec2 p, in vec2 b)
{
    vec2 q = abs(p);  // 坐标轴对称
    // 计算的是线段b的中点到p点的向量，在b上的投影限制到[-1, 1]
    // 负数表示向量偏向于y轴， 正数表示偏向x轴
    float h = clamp((-2.0*ndot(q,b)+ndot(b,b))/dot(b,b),-1.0, 1.0);
    /* 实际上h从-1到1的滑动过程，[0.5*b*vec2(1.0-h,1.0+h)] 表示一条从原点出发，
       终点在向量b上由左上到右下的滑动的向量 */
    float d = length( q - 0.5*b*vec2(1.0-h,1.0+h) );
    // 符号：可计算(b.x, -b.y)和(p.x, p.y-b.y)的叉积，得两向量的相对位置
    return d * sign( q.x*b.y + q.y*b.x - b.x*b.y );
}
/**
 * 等边三角形：  1. 原点在三角形中心点
 *              2. r表示边长的一半（不是中心点到顶点的距离）
*/
float sdEquilateralTriangle(in vec2 p, in float r )
{
    const float k = sqrt(3.0);
    p.x = abs(p.x);
    // 由于三角形可以看成是由三个部分绕中心点三个角度生成的，x负半轴不用考虑
    // 所以只需要考虑在区域 1的那部分，这一部分可以通过关于直线y=-1/sqrt(3)*x对称映射到下方的三分之一
    // 映射关系如下：
    if( p.x+k*p.y>0.0 ) p=vec2(p.x-k*p.y,-k*p.x-p.y)/2.0;
    // 一切都归一到只需要看区域 2-3-4即可
    // x在减去r后，若其值-2*r<x<0，说明原来范围是-r<0<r,即知道点p在x轴上处于三角形内部，只需看y轴长度即可
    // 否则，需要原x轴坐标减去左/右下角坐标x值
    p.x -= r;
    p.y += r/k;
    p.x -= clamp( p.x, -2.0*r, 0.0 );
    return -length(p)*sign(p.y);
}
/**
* 等腰三角形：  1. 原点位于顶角，垂直于底边的高和y轴重合
*              2. q表示右腰的向量，一般q.y为负（此时顶角是朝上的）
*/
float sdTriangleIsosceles( in vec2 p, in vec2 q )
{
    p.x = abs(p.x);
    // 分为两种可能的最小距离： 1.与腰的距离， 2.与底的距离
    // 1. 与腰
    vec2 a = p - q*clamp( dot(p,q)/dot(q,q), 0.0, 1.0 );
    // 2. 与底
    vec2 b = p - q*vec2( clamp( p.x/q.x, 0.0, 1.0 ), 1.0 );
    float k = sign( q.y );
    float d = min(dot( a, a ), dot( b, b ));
    float s = max(k*(p.x*q.y-p.y*q.x), k*(p.y-q.y)); // 两项都小于零才是取负，即内部
    // float s = k*(p.y-q.y)>0.0?((k*(p.x*q.y-p.y*q.x))>0.0?1.0:-1.0):-1.0; // 可用此句替换
	return sqrt(d)*sign(s);
}
/**
* 一般三角形：  1. 原点不限
*              2. 三条边的向量都给出，为 p0,p1,p2
*/
float sdTriangle( in vec2 p, in vec2 p0, in vec2 p1, in vec2 p2 )
{
    vec2 e0 = p1-p0, e1 = p2-p1, e2 = p0-p2;
    vec2 v0 = p -p0, v1 = p -p1, v2 = p -p2;
    // 分别计算过p点垂直于三条边的向量，箭头指向p点
    vec2 pq0 = v0 - e0*clamp( dot(v0,e0)/dot(e0,e0), 0.0, 1.0 );
    vec2 pq1 = v1 - e1*clamp( dot(v1,e1)/dot(e1,e1), 0.0, 1.0 );
    vec2 pq2 = v2 - e2*clamp( dot(v2,e2)/dot(e2,e2), 0.0, 1.0 );
    // 由于不清楚传入的三个点是顺时针还是逆时针顺序，先确定好基本符号
    // 若s是-1，说明传入是逆时针
    // 假设规定传入都是顺时针顺序，则s为1，可无视
    float s = sign( e0.x*e2.y - e0.y*e2.x );
    // 这里的 d并非具有什么实际几何意义的向量，而是作为一个数据的集合来使用
    // 它的第一个分量d.x表示p点与各边长度的平方中的最小值，它的第二个分量可以用来判断内部外部
    // 假如点P在三角形内部，那么参与比较的三个式子都会是正数，它们中的最小值也将是正数
    // 若在外部，则至少有一个式子是负的，取最小值后d.y也将是负值
    vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)),
                     vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))),
                     vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x)));
    // 若d.y为负数，说明在三角形外，不要漏看下面一行的负号
    return -sqrt(d.x)*sign(d.y);
}


void main(){
    vec2 vUv=gl_FragCoord.xy/u_resolution;
    vUv = (vUv - 0.5) * 2.;
    // vUv -= 0.5;
    
    // float d = sdBox(vUv, vec2(0.6,0.6));
    // float d = sdSegment(vUv, vec2(0.,0.), vec2(1.,1.));
    // float d = sdRhombus(vUv, vec2(0.4,0.2));
    // float d = sdEquilateralTriangle(vUv, 0.5);
    // float d = sdTriangleIsosceles(vUv, vec2(0.5,0.6));
    float d = sdTriangle(vUv, vec2(0.,0.6),vec2(0.2,0.2),vec2(0.8,0.8));
    float angel = atan(vUv.x, vUv.y);
    d = smoothstep(0., 0.02, d);

    gl_FragColor.rgb=vec3(d);
    gl_FragColor.a=1.;
}